
#version 330 core
out vec4 FragColor;

in VS_OUT {
				vec3 FragPos;
				vec3 Normal;
				vec2 TexCoords;
				vec4 FragPosLightSpace;
} fs_in;

struct LightValue{
		vec3 position;
		float ambient;
		float diffuse;
		float specular;
};

uniform sampler2D diffuseTexture;
uniform sampler2D shadowMap;

//uniform vec3 lightPos;
uniform LightValue light;
uniform vec3 viewPos;

float ShadowCalculation(vec4 fragPosLightSpace){
		// perform perspective divide
		vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;

		// transform to [0,1] range
		projCoords = projCoords * 0.5 + 0.5;

		//get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
		float closestDepth = texture(shadowMap, projCoords.xy).r;

		// get depth of current fragment from light's perspective
		float currentDepth = projCoords.z;

		// calculate bias (based on depth map resolution and slope)
		vec3 normal = normalize(fs_in.Normal);
		vec3 lightDir = normalize(light.position - fs_in.FragPos);
		float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);

		// check whether current frag pos is in shadow
				// PCF
		float shadow = 0.0;
		vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
		for(int x = -1; x <= 1; ++x){
				for(int y = -1; y <= 1; ++y){
						float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
						shadow += currentDepth - bias > pcfDepth  ? 1.0 : 0.0;
				}
		}
		shadow /= 9.0;

		// keep the shadow at 0.0 when outside the far_plane region of the light's frustum.
		if(currentDepth > 1.0)
				shadow = 0.0;

		return shadow;
//				return closestDepth;
}

void main(){
		vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
		vec3 normal = normalize(fs_in.Normal);


		// ambient
		vec3 ambient = light.ambient * color;

		// diffuse
		vec3 lightDir = normalize(light.position - fs_in.FragPos);
		float diff = max(dot(lightDir, normal), 0.0);
		vec3 diffuse = diff * color * light.diffuse;

		// specular
		vec3 viewDir = normalize(viewPos - fs_in.FragPos);
		vec3 reflectDir = reflect(-lightDir, normal);
		float spec = 0.0;
		vec3 halfwayDir = normalize(lightDir + viewDir);
		spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
		vec3 specular = spec * color * light.specular;

		// calculate shadow
		float shadow = ShadowCalculation(fs_in.FragPosLightSpace);
//				FragColor = vec4(shadow, shadow, shadow, 1.0f);
		vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;

		FragColor = vec4(lighting, 1.0);

}
